﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;

namespace Light.Utility
{
    /// <summary>
    /// DataTable与实体互相转换的工具类
    /// </summary>
    public class DataTableHelper
    {
        /// <summary>
        /// 将DataTable转换成 T 类型对象的集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <param name="customObjPropertyNames">自定义类型属性的属性名s</param>
        /// <returns></returns>
        public static List<T> ConvertTo<T>(DataTable dt, params string[] customObjPropertyNames) where T : class, new()
        {
            List<T> models = new List<T>();

            IList<string> propertyNames = ReflectionHelper.GetProperties<T>();
            int rowCount = dt.Rows.Count;
            for (int i = 0; i < rowCount; i++)
            {
                DataRow row = dt.Rows[i];
                if (IsEmptyRow(row))
                {
                    continue;
                }
                T model = new T();

                //T类中系统类型属性
                foreach (var pName in propertyNames)
                {
                    if (dt.Columns.Contains(pName)) //表格中找不到匹配的列名，则用默认列名
                    {
                        object value = row[pName];
                        if (value != null && value != System.DBNull.Value && !String.IsNullOrEmpty(value.ToString()))
                        {
                            ReflectionHelper.SetPropertyValue(model, pName, value);
                        }
                    }
                }

                //T类中自定义类型属性的属性
                foreach (var pName in customObjPropertyNames)
                {
                    if (dt.Columns.Contains(pName)) //表格中找不到匹配的列名，则用默认列名
                    {
                        object value = row[pName];
                        if (value != null && value != System.DBNull.Value && !String.IsNullOrEmpty(value.ToString()))
                        {
                            ReflectionHelper.SetPropertyValue(model, pName, value);
                        }
                    }
                }

                models.Add(model);
            }

            return models;
        }

        /// <summary>
        /// 表行转化成实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="row"></param>
        /// <returns></returns>
        public static T ConvertTo<T>(DataRow row) where T : class, new()
        {
            if (IsEmptyRow(row))
            {
                return null;
            }
            T model = new T();
            IList<string> propertyNames = ReflectionHelper.GetProperties<T>();
            foreach (var pName in propertyNames)
            {
                if (row.Table.Columns.Contains(pName)) //表格中找不到匹配的列名，则用默认列名
                {
                    object value = row[pName];
                    if (value != null && value != System.DBNull.Value && !String.IsNullOrEmpty(value.ToString()))
                    {
                        ReflectionHelper.SetPropertyValue(model, pName, value);
                    }
                }
            }
            return model;
        }

        /// <summary>
        /// 将实体转化成DataTable
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="models"></param>
        /// <returns></returns>
        public static DataTable ToDataTable<T>(T[] models)
        {
            string tableName = ReflectionHelper.GetDisplayName<T>() + "_" + DateTime.Now.ToString("yyyyMMdd_hhmmss");
            DataTable dt = new DataTable(tableName);

            PropertyInfo[] pinfos = typeof(T).GetProperties();
            foreach (var pinfo in pinfos)
            {
                if (!dt.Columns.Contains(pinfo.Name))
                {
                    DataColumn column = new DataColumn(pinfo.Name);
                    if (models != null && models.Length > 0)
                    {

                        if (pinfo.PropertyType == typeof(DateTime) ||
                            pinfo.PropertyType == typeof(String) ||
                            pinfo.PropertyType == typeof(int) ||
                            pinfo.PropertyType == typeof(Double))
                        {
                            column.DataType = pinfo.PropertyType;
                        }
                        else if (pinfo.PropertyType == typeof(Decimal))
                        {
                            column.DataType = typeof(Double);
                        }
                    }
                    dt.Columns.Add(column);
                }
            }
            foreach (T model in models)
            {
                DataRow row = dt.NewRow();

                foreach (var pinfo in pinfos)
                {
                    object value = ReflectionHelper.GetPropertyValue<T>(model, pinfo.Name);

                    if (value is Enum)
                    {
                        row[pinfo.Name] = EnumHelper.GetEnumDesc((Enum)value);
                    }
                    else if (value is DateTime)
                    {
                        row[pinfo.Name] = Convert.ToDateTime(value).ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    else if (value is Boolean)
                    {
                        row[pinfo.Name] = Boolean.Parse(value.ToString()) ? 1 : 0;
                    }
                    else
                    {
                        row[pinfo.Name] = value;
                    }
                }

                dt.Rows.Add(row);
            }
            return dt;
        }


        /// <summary>
        /// 获取DataTable转换成需要的新DataTable
        /// </summary>
        /// <param name="dtSource">源数据</param>
        /// <param name="columns">需要过滤的列</param>
        /// <param name="dic_OldName_NewName">需要替换的 旧列名-新列名 字典,可为null</param>
        /// <returns></returns>
        public static DataTable ToDataTable(DataTable dtSource, OperateColumn columns)
        {
            if (columns != null)
            {
                List<string> deletes = new List<string>();
                foreach (DataColumn col in dtSource.Columns)
                {
                    if (!columns.IsRetain(col.ColumnName))
                        deletes.Add(col.ColumnName);
                }
                foreach (var col in deletes)
                {
                    RemoveColumn(dtSource, col);
                }
            }
            if (columns.HasNewNames)
            {
                Dictionary<string, string> dic = columns.GetNewNames();
                foreach (var oldColName in dic.Keys)
                {
                    RenameColumn(dtSource, oldColName, dic[oldColName]);
                }
            }
            return dtSource;
        }

        /// <summary>
        /// DataTable是否包含指定列集合
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columns"></param>
        /// <returns></returns>
        public static bool Contains(DataTable dt, params string[] columns)
        {
            bool has = true;
            foreach (var column in columns)
            {
                if (!dt.Columns.Contains(column))
                {
                    has = false;
                    break;
                }
            }
            return has;
        }


        /// <summary>
        /// 判断表格行是否为空行
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public static bool IsEmptyRow(DataRow row)
        {
            int length = row.Table.Columns.Count;
            for (int i = 0; i < length; i++)
            {
                if (!IsEmptyCell(row[i]))
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 判断单元格是否为空
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static bool IsEmptyCell(object cell)
        {
            if (cell != DBNull.Value || cell != null && !String.IsNullOrEmpty(cell.ToString()))
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// 添加列，如果列名已存在，则不添加，忽略
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="column"></param>
        public static void AddColumn(DataTable dt, DataColumn column)
        {
            if (!dt.Columns.Contains(column.ColumnName))
            {
                dt.Columns.Add(column);
            }
        }

        /// <summary>
        /// 添加列，如果列名已存在，则不添加，忽略
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        public static void AddColumn(DataTable dt, string columnName)
        {
            DataColumn column = new DataColumn(columnName);
            AddColumn(dt, column);
        }

        /// <summary>
        /// 添加列，如果列名已存在，则不添加，忽略
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        /// <param name="columnType"></param>
        public static void AddColumn(DataTable dt, string columnName, Type columnType)
        {
            DataColumn column = new DataColumn(columnName, columnType);
            AddColumn(dt, column);
        }

        /// <summary>
        /// 删除指定的列，不存在，则忽略
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnNames">列名，可传多个</param>
        public static void RemoveColumn(DataTable dt, params string[] columnNames)
        {
            foreach (var columnName in columnNames)
            {
                if (dt.Columns.Contains(columnName))
                    dt.Columns.Remove(columnName);
            }
        }

        /// <summary>
        /// 重命名列名
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="columnName"></param>
        /// <param name="newName"></param>
        public static void RenameColumn(DataTable dt, string columnName, string newName)
        {
            if (dt.Columns.Contains(columnName))
                dt.Columns[columnName].ColumnName = newName;
        }
    }
}
